package admin

import (
	"context"
	"fmt"
	"grpc.getaway.adminspro.padmins.com/internal/rpc/module/admin/adminLogic"
	"grpc.getaway.adminspro.padmins.com/internal/rpc/utils/database"
	"grpc.getaway.adminspro.padmins.com/pkg/config/businessError"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/db"
	"grpc.getaway.adminspro.padmins.com/pkg/libs/utils"
	pbAdmin "grpc.getaway.adminspro.padmins.com/pkg/proto/admin"
	"math/rand"
	"regexp"
	"strconv"
)

func (rpc *admin) AdminAdd(ctx context.Context, pb *pbAdmin.AdminAddReq) (*pbAdmin.AdminAddResp, error) {
	roleIds := make([]interface{}, len(pb.RoleId))
	Db := database.Db.GetDefaultDb(ctx)

	for i, roleId := range pb.RoleId {
		roleIds[i] = roleId
	}

	matched, _ := regexp.MatchString("^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$", pb.Admin.Email)
	if matched != true {
		return nil, businessError.ErrorInfoToRpcError(businessError.AdminEmailError)
	}
	if pb.Admin.Nickname == "" {
		return nil, businessError.ErrorInfoToRpcError(businessError.AdminNicknameError)
	}
	matched, _ = regexp.MatchString("^[a-zA-Z][a-zA-Z0-9]{5,19}$", pb.Admin.Username)
	if matched != true {
		return nil, businessError.ErrorInfoToRpcError(businessError.AdminUsernameError)
	}
	if len(pb.Admin.Password) < 6 {
		return nil, businessError.ErrorInfoToRpcError(businessError.AdminPasswordError)
	}
	if len(roleIds) == 0 {
		return nil, businessError.ErrorInfoToRpcError(businessError.AdminRoleIdsEmpty)
	}
	if _, ok := adminLogic.List()["status"][strconv.FormatInt(int64(pb.Admin.Status), 10)]; !ok {
		return nil, businessError.ErrorInfoToRpcError(businessError.AdminStatusError)
	}

	hasEmail, dbErr := Db.Find("select * from admin where email=?", pb.Admin.Email)
	if dbErr != nil {
		return nil, businessError.ErrorInfoToRpcError(businessError.DbError(dbErr))
	}

	if hasEmail != nil {
		return nil, businessError.ErrorInfoToRpcError(businessError.AdminEmailExists)
	}

	hasUsername, dbErr := Db.Find("select * from admin where username=?", pb.Admin.Username)

	if dbErr != nil {
		return nil, businessError.ErrorInfoToRpcError(businessError.DbError(dbErr))
	}

	if hasUsername != nil {
		return nil, businessError.ErrorInfoToRpcError(businessError.AdminUsernameExists)
	}

	if pb.OperaterId != 0 {
		if len(utils.ArrayDiff(roleIds, adminLogic.GetChildrenRoleIds(ctx, pb.OperaterId))) > 0 {
			return nil, businessError.ErrorInfoToRpcError(businessError.AdminRoleIdsNotIn)
		}
	}

	salt := utils.Md5(strconv.FormatInt(int64(rand.Intn(99999-10000)+10000), 10) + utils.Date("Y-m-d H:i:s"))[:6]
	password := utils.Md5(utils.Md5(pb.Admin.Password) + salt)

	id, e := Db.TransactionFunc(func(Db *db.Db) (interface{}, error) {
		_, dbErr := Db.Insert("admin", map[string]interface{}{
			"email":       pb.Admin.Email,
			"username":    pb.Admin.Username,
			"nickname":    pb.Admin.Nickname,
			"password":    password,
			"salt":        salt,
			"avatar":      pb.Admin.Avatar,
			"status":      pb.Admin.Status,
			"create_time": utils.Date("Y-m-d H:i:s"),
			"update_time": utils.Date("Y-m-d H:i:s"),
		})

		if dbErr != nil {
			return nil, businessError.ErrorInfoToRpcError(businessError.DbError(dbErr))
		}

		id, dbErr := Db.LastInsertId()

		if dbErr != nil {
			return nil, businessError.ErrorInfoToRpcError(businessError.DbError(dbErr))
		}

		for _, roleId := range roleIds {
			if roleId == "" || fmt.Sprintf("%v", roleId) == "0" {
				return nil, businessError.ErrorInfoToRpcError(businessError.AdminRoleIdsError)
			}

			rowCount, dbErr := Db.Insert("admin_role_access", map[string]interface{}{
				"admin_id":    id,
				"role_id":     roleId,
				"update_time": utils.Date("Y-m-d H:i:s"),
				"create_time": utils.Date("Y-m-d H:i:s"),
			})

			if dbErr != nil {
				return nil, businessError.ErrorInfoToRpcError(businessError.DbError(dbErr))
			}

			if rowCount <= 0 {
				return nil, businessError.ErrorInfoToRpcError(businessError.AdminAddError)
			}
		}

		return id, nil
	})

	if e != nil {
		return nil, e
	}

	return &pbAdmin.AdminAddResp{
		Id: id.(int64),
	}, nil
}
